/*
 * @Author: wangcb
 * @Email: wangcbgg@163.com
 * @Date: 2021-10-21 17:05:52
 * @LastEditTime: 2021-11-17 11:08:39
 * 通用播放器方法封装
 */
/**
 * 播放器状态枚举
 * @readonly
 * @enum {PLAY | FORWARD | REWIND | PAUSE | STOP | ERROR}
 */
export var STATUS;
(function (STATUS) {
    /** 初始化 */ STATUS["INIT"] = "INIT";
    /** 播放 */ STATUS["PLAY"] = "PLAY";
    /** 快进倍速播放 */ STATUS["FORWARD"] = "FORWARD";
    /** 快退倍速播放 */ STATUS["REWIND"] = "REWIND";
    /** 暂停 */ STATUS["PAUSE"] = "PAUSE";
    /** 停止 */ STATUS["STOP"] = "STOP";
    /** 错误 */ STATUS["ERROR"] = "ERROR";
})(STATUS || (STATUS = {}));
/**
 * Utility事件类型对象
 * @readonly
 */
export const UtilityEvent = {
    /** 当前环境不支持Utility */ UNSUPPORTED: 'UNSUPPORTED',
    /** 当按下 CH+, CH-和数字键,机顶盒将打开下一个频道时触发 */ GO_CHANNEL: 'EVENT_GO_CHANNEL',
    /** 资源空闲时触发 */ STB_RESOURCE_IDLE: 'EVENT_STB_RESOURCE_IDLE',
    /** 恢复播放 */ IPTV_RESUME: 'EVENT_IPTV_RESUME',
    /** 媒体播放到末端时触发 */ MEDIA_END: 'EVENT_MEDIA_END',
    /** 媒体播放到起始端时触发 */ MEDIA_BEGINING: 'EVENT_MEDIA_BEGINING',
    /** 发生异常时触发 */ MEDIA_ERROR: 'EVENT_MEDIA_ERROR',
    /** 当媒体播放器的 playback mode 发生改变的时候触发 */ PLAYMODE_CHANGE: 'EVENT_PLAYMODE_CHANGE',
    /** 当机顶盒定时提醒时触发 */ REMINDER: 'EVENT_REMINDER',
    /** 当增值业务客户端产生下载、启动、退出、出错等状态发生时触发 */ JVM_CLIENT: 'EVENT_JVM_CLIENT'
};
/**
 * 通用播放器类
 * @class CommonPlayer
 */
class CommonPlayer {
    constructor(config, type) {
        /**
         * 播放器实例
         * @private
         * @type {(CommonPlayer | null)}
         */
        this.player = null;
        /**
         * 播放器位置及尺寸配置
         * @typedef IBaseConfig
         * @property {number} left 播放器left值
         * @property {number} top 播放器top值
         * @property {number} width 播放器宽度
         * @property {number} height 播放器高度
         */
        /**
         * 基础配置
         * @type {IBaseConfig}
         */
        this.baseConfig = { left: 0, top: 0, width: 1920, height: 1080 };
        /**
         * 音量UI
         * @type {(HTMLElement | null)}
         */
        this.volumeBox = null;
        /**
         * 音量timer
         * @private
         * @type {(number | null)}
         */
        this.volumeTimer = null;
        /**
         * 音量UI自动隐藏间隔
         * @type {number}
         */
        this.volumeInterval = 3000;
        /**
         * 最大音量
         * @private
         * @type {number}
         */
        this.totalVolume = 100;
        /**
         * 当前音量
         * @private
         * @type {number}
         */
        this.nowVolume = 50;
        /**
         * 播放器类型 0 点播 1 直播
         * @type {number}
         */
        this.type = 0;
        /**
         * 音量每次加减步长
         * @type {number}
         */
        this.step = 5;
        /**
         * 静音标志
         * @private
         * @type {number}
         */
        this.muteFlag = 0;
        /**
         * 倍速快进值
         * @type {number}
         */
        this.forwardSpeed = 1;
        /**
         * 倍速快退值
         * @type {number}
         */
        this.rewindSpeed = 1;
        /**
         * 频道号
         * @private
         * @type {number}
         */
        this.channelNumber = 0;
        /**
         * 实例id
         * @private
         * @type {number}
         */
        this.instanceId = -1;
        /**
         * 播放时间timer
         * @private
         * @type {(number | null)}
         */
        this.playTimer = null;
        /**
         * 播放器状态
         * @private
         * @type {STATUS}
         */
        this.status = STATUS.INIT;
        this.baseConfig = config;
        try {
            // @ts-ignore stb自带播放器对象
            const mp = type ? new MediaPlayer(type) : new MediaPlayer();
            this.instanceId = mp.getNativePlayerInstanceID();
            const playListFlag = 0, videoDisplayMode = 0, muteFlag = 0, subtitleFlag = 0, videoAlpha = 0, cycleFlag = 1, randomFlag = 0, autoDelFlag = 0, useNativeUIFlag = 0;
            mp.initMediaPlayer(this.instanceId, playListFlag, videoDisplayMode, config.height || 100, config.width || 100, config.left || 0, config.top || 0, muteFlag, useNativeUIFlag, subtitleFlag, videoAlpha, cycleFlag, randomFlag, autoDelFlag);
            mp.setNativeUIFlag(useNativeUIFlag);
            mp.setMuteUIFlag(muteFlag);
            mp.setAudioVolumeUIFlag(0);
            mp.setAudioTrackUIFlag(0);
            mp.setProgressBarUIFlag(0);
            mp.setChannelNoUIFlag(0);
            mp.setAllowTrickmodeFlag(0);
            this.nowVolume = mp.getVolume();
            this.muteFlag = mp.getMuteFlag();
            this.setVolume(this.nowVolume);
            this.setMuteFlag(this.muteFlag);
            this.channelNumber = mp.getChannelNum();
            // @ts-ignore
            this.player = mp;
        }
        catch {
            console.warn('[MediaPlayer] is not supported in this environment');
        }
    }
    /**
     * 自动隐藏音量UI
     * @private
     */
    autoHideVolumeBox() {
        if (!this.volumeBox)
            return;
        if (this.volumeBox.style.visibility !== 'visible')
            this.volumeBox.style.visibility = 'visible';
        if (this.volumeTimer)
            clearTimeout(this.volumeTimer);
        this.volumeTimer = setTimeout(() => {
            if (this.volumeBox)
                this.volumeBox.style.visibility = 'hidden';
        }, this.volumeInterval);
    }
    /**
     * 切换播放
     * @returns {STATUS} 播放器状态
     */
    togglePlay() {
        if (this.player) {
            if (this.status === STATUS.PLAY) {
                this.pause();
            }
            else {
                this.resume();
            }
        }
        return this.status;
    }
    /**
     * 恢复播放
     */
    resume() {
        if (this.player) {
            this.player.resume();
            this.setStatus(STATUS.PLAY);
            this.resetFastRate();
            this.updateProgress();
        }
    }
    /**
     * 暂停播放
     */
    pause() {
        if (this.player) {
            this.player.pause();
            this.setStatus(STATUS.PAUSE);
            this.stopProgress();
        }
    }
    /**
     * 停止播放
     */
    stop() {
        if (this.player) {
            this.player.stop();
            this.setStatus(STATUS.STOP);
            this.stopProgress();
        }
    }
    /**
     * 设置音量UI
     * @param {HTMLElement} volumeBox 音量UI的dom对象
     */
    setVolumeBox(volumeBox) {
        this.volumeBox = volumeBox;
    }
    /**
     * 设置当前音量
     * @param {number} volume 音量值
     */
    setVolume(volume) {
        if (this.player) {
            if (volume >= this.totalVolume)
                volume = this.totalVolume;
            if (volume <= 0) {
                this.setMuteFlag(1);
                volume = 0;
            }
            else {
                this.setMuteFlag(0);
            }
            this.player.setVolume(volume);
            this.nowVolume = volume;
        }
    }
    /**
     * 获取当前音量
     * @returns {number} 当前音量
     */
    getVolume() {
        if (this.player)
            return this.player.getVolume();
        return 0;
    }
    /**
     * 增大音量
     * @returns {number} 当前音量
     */
    volumeUp() {
        if (this.player) {
            if (this.nowVolume < this.totalVolume)
                this.nowVolume += this.step;
            this.setVolume(this.nowVolume);
            this.autoHideVolumeBox();
        }
        return this.nowVolume;
    }
    /**
     * 降低音量
     * @returns {number} 当前音量
     */
    volumeDown() {
        if (this.player) {
            if (this.nowVolume > 0) {
                this.nowVolume -= this.step;
            }
            this.setVolume(this.nowVolume);
            this.autoHideVolumeBox();
        }
        return this.nowVolume;
    }
    /**
     * 设置静音标志
     * @param {number} muteFlag 0为非静音 1为静音
     */
    setMuteFlag(muteFlag) {
        if (this.player) {
            this.muteFlag = muteFlag;
            this.player.setMuteFlag(muteFlag);
        }
    }
    /**
     * 获取静音标志
     * @returns {number} 静音标志 0为非静音 1为静音
     */
    getMuteFlag() {
        if (this.player)
            return this.player.getMuteFlag();
        return 0;
    }
    /**
     * 静音切换
     * @returns {number} 静音标志 0为非静音 1为静音
     */
    toggleMute() {
        if (this.player) {
            this.muteFlag = this.muteFlag === 0 ? 1 : 0;
            this.setMuteFlag(this.muteFlag);
            this.autoHideVolumeBox();
        }
        return this.muteFlag;
    }
    /**
     * 获取影片总时长
     * @returns {number} 影片总时长(单位s)
     */
    getMediaDuration() {
        if (this.player) {
            const time = this.player.getMediaDuration();
            return this.type ? time : +time;
        }
        return 0;
    }
    /**
     * 获取当前播放时间
     * @returns {number} 当前播放时间(单位s)
     */
    getCurrentPlayTime() {
        if (this.player) {
            const time = this.player.getCurrentPlayTime();
            return this.type ? time : +time;
        }
        return 0;
    }
    /**
     * 倍速快进
     * @param {number} [speed] 速率
     * @returns {number} 当前播放速率
     */
    fastForward(speed) {
        this.setStatus(STATUS.FORWARD);
        this.rewindSpeed = 1;
        if (this.player && undefined !== speed) {
            this.player.fastForward(speed);
            this.forwardSpeed = speed;
            return this.forwardSpeed;
        }
        if (this.forwardSpeed < 32)
            this.forwardSpeed *= 2;
        if (this.player)
            this.player.fastForward(this.forwardSpeed);
        return this.forwardSpeed;
    }
    /**
     * 倍速快退
     * @param {number} [speed] 速率
     * @returns {number} 当前播放速率
     */
    fastRewind(speed) {
        this.setStatus(STATUS.REWIND);
        this.forwardSpeed = 1;
        if (this.player && undefined !== speed) {
            this.player.fastRewind(speed);
            this.rewindSpeed = speed;
            return this.rewindSpeed;
        }
        if (this.rewindSpeed < 32)
            this.rewindSpeed *= 2;
        if (this.player)
            this.player.fastRewind(-this.rewindSpeed);
        return this.rewindSpeed;
    }
    /**
     * 重置倍率
     */
    resetFastRate() {
        this.forwardSpeed = 1;
        this.rewindSpeed = 1;
    }
    /**
     * 获取当前频道号
     * @returns {number} 当前频道号
     */
    getChannelNum() {
        if (this.player) {
            this.channelNumber = this.player.getChannelNum();
            return this.channelNumber;
        }
        return -1;
    }
    /**
     * 跳到媒体起始点播放
     */
    gotoStart() {
        if (this.player) {
            this.setStatus(STATUS.PLAY);
            this.player.gotoStart();
            this.onProgress(0, this.getMediaDuration());
            this.updateProgress();
        }
    }
    /**
     * 跳到媒体末端播放
     */
    gotoEnd() {
        if (this.player) {
            this.setStatus(STATUS.PLAY);
            this.player.gotoEnd();
            this.onProgress(this.getCurrentPlayTime(), this.getMediaDuration());
            this.updateProgress();
        }
    }
    /**
     * 返回音频PID,如果正在播放返回当前播放的PID,否则返回第一个PID
     * @returns {(number | null)}
     */
    getAudioPID() {
        return this.player && this.player.getAudioPID();
    }
    /**
     * 指定播放音频id
     * @param {string} pid 音频id
     */
    setAudioPID(pid) {
        if (this.player)
            this.player.setAudioPID(pid);
    }
    /**
     * MediaPlayer对象对应的视频窗口的显示模式
     *
     * 0: 按setVideoDisplayArea()中设定的left, top, height, width属性所指定的位置和大小来显示视频
     *
     * 1: 全屏显示,按全屏高度和宽度显示(默认值)
     *
     * 2: 按宽度显示,指在不改变原有图像纵横比的情况下按全屏宽度显示
     *
     * 3: 按高度显示,指在不改变原有图像纵横比的情况下按全屏高度显示
     *
     * 255: 视频显示窗口将被关闭,它将在保持媒体流连接的前提下,隐藏视频窗口,如果流媒体播放没有被暂停,将继续播放音频
     * @param {number} mode
     */
    setVideoDisplayMode(mode) {
        if (this.player)
            this.player.setVideoDisplayMode(mode);
    }
    /**
     * 每次调用该函数后,视频显示窗口并不会被立即重新刷新以反映更改后的显示效果只有等到显式调用refreshVideoDisplay()后才会刷新
     * @param {number} left left坐标
     * @param {number} top top坐标
     * @param {number} width 长
     * @param {number} height 宽
     */
    setVideoDisplayArea(left, top, width, height) {
        if (this.player)
            this.player.setVideoDisplayArea(left, top, width, height);
    }
    /**
     * 根据videoDisplayMode,videoDisplayArea属性,调整视频的显示
     */
    refreshVideoDisplay() {
        if (this.player)
            this.player.refreshVideoDisplay();
    }
    /**
     * 释放播放器
     * @param {number} instanceId 实例id
     */
    releaseMediaPlayer(instanceId) {
        if (this.player) {
            this.player.stop();
            if (this.type === 1)
                this.player.leaveChannel();
            this.player.releaseMediaPlayer(instanceId);
            this.stopProgress();
        }
    }
    /**
     * 获取当前播放实例id
     * @returns {number} 实例id
     */
    getNativePlayerInstanceID() {
        if (this.player)
            return this.player.getNativePlayerInstanceID();
        return -1;
    }
    /**
     * 启动播放
     * @param {string} mediaCode 内容唯一标识(点播为内容ID | 直播为频道ID)
     * @param {string} mediaURL 点播为播放地址 | 直播为频道号
     * @param {number} [breakpoint=0] 断点时间戳(单位s)
     * @param {number} [mediaType=2] 媒体类型(默认 2)
     *
     * 1: TYPE_CHANNEL 2: TYPE_VOD 3: TYPE_TVOD 4: TYPE_MUSIC
     * @param {number} [streamType=2] 流类型(默认 2)
     *
     * 1: PS 2: TS 3: MP4 4: ASF
     */
    startPlay(mediaCode, mediaURL, breakpoint = 0, mediaType = 2, streamType = 2) {
        if (this.player) {
            this.refreshVideoDisplay();
            mediaURL = mediaURL.trim();
            const json = `[{mediaUrl:"${mediaURL}",mediaCode:"${mediaCode}",mediaType:${mediaType},audioType:1,videoType:1,streamType:${streamType},drmType:1,fingerPrint:0,copyProtection:1,allowTrickmode:1,startTime:0,endTime:0,entryID:"jsonEntry1"}]`;
            this.setSingleMedia(json);
            if (breakpoint) {
                this.playByTime(1, breakpoint);
            }
            else {
                this.playFromStart();
            }
            this.setVideoDisplayArea(this.baseConfig.left, this.baseConfig.top, this.baseConfig.width, this.baseConfig.height);
            this.setVideoDisplayMode(0);
            this.refreshVideoDisplay();
        }
    }
    /**
     * 开发环境下的起播方法
     * @param playUrl 播放地址
     * @param breakpoint 断点时间
     */
    startPlayDev(playUrl, breakpoint = 0) {
        this.setSingleMedia(playUrl);
        if (this.player) {
            if (breakpoint) {
                this.playByTime(1, breakpoint);
            }
            else {
                this.playFromStart();
            }
        }
    }
    /**
     * 设置media参数
     * @param {string} json media参数
     */
    setSingleMedia(json) {
        if (this.player)
            this.player.setSingleMedia(json);
    }
    /**
     * 从片头开始播放
     */
    playFromStart() {
        if (this.player) {
            this.setStatus(STATUS.PLAY);
            this.player.playFromStart();
            this.updateProgress();
        }
    }
    /**
     * 重头播放
     */
    restartPlay() {
        if (this.player) {
            this.setStatus(STATUS.PLAY);
            this.player.playFromStart();
        }
    }
    /**
     * 加入频道
     * @param {number} channelNumber 频道号
     */
    joinChannel(channelNumber) {
        if (this.player) {
            this.setStatus(STATUS.PLAY);
            this.setVideoDisplayArea(this.baseConfig.left, this.baseConfig.top, this.baseConfig.width, this.baseConfig.height);
            this.setVideoDisplayMode(0);
            this.refreshVideoDisplay();
            this.player.joinChannel(channelNumber);
        }
    }
    /**
     * 退出频道
     */
    leaveChannel() {
        if (this.player) {
            this.setStatus(STATUS.STOP);
            this.player.leaveChannel();
        }
    }
    /**
     * 从时间戳位置开始播放
     * @param {number} [type=1] 播放类型
     *
     * 1 Normal Play Time (NPT) 2 Absolute Time (ClockTime)
     * @param {number} [timestamp=0] 时间戳
     * @param {number} [speed=1] 播放速度
     */
    playByTime(type = 1, timestamp = 0, speed = 1) {
        if (this.player) {
            this.setStatus(STATUS.PLAY);
            this.player.playByTime(type, timestamp, speed);
            this.updateProgress();
        }
    }
    /**
     * 设置播放器状态
     * @param {STATUS} status
     */
    setStatus(status) {
        if (this.player)
            this.status = status;
    }
    /**
     * 获取播放器状态
     * @returns {STATUS} 播放器状态
     */
    getStatus() {
        if (this.player)
            return this.status;
        return STATUS.ERROR;
    }
    /**
     * 监听进度
     * @param {number} currentTime 当前播放时间点(单位s)
     * @param {number} totalTime 当前影片总时长(单位s)
     */
    onProgress(currentTime, totalTime) { }
    /** 播放结束回调 */
    playEnd() { }
    /**
     * 更新进度
     */
    updateProgress() {
        this.stopProgress();
        this.playTimer = setTimeout(() => {
            const currentTime = this.getCurrentPlayTime();
            const totalTime = this.getMediaDuration();
            this.onProgress(currentTime, totalTime);
            if (currentTime >= totalTime) {
                this.stopProgress();
                this.playEnd();
            }
            this.updateProgress();
        }, 1000);
    }
    /**
     * 停止进度
     */
    stopProgress() {
        if (this.playTimer)
            clearTimeout(this.playTimer);
    }
}
/**
 * 创建通用点播播放器实例
 * @param {(number | IBaseConfig)} config 播放器配置 当传入数字类型时表示left参数值
 * @param {...Array<number>} args top、width、height参数值
 * @returns {CommonPlayer} 播放器实例
 * @example
 * let player = Player.createPlayer({ left: 0, top: 0, width: 1920, height: 1080 });
 * let player = Player.createPlayer(0, 0, 1920, 1080);
 */
export function createPlayer(config, ...args) {
    let player;
    if (typeof config === 'number') {
        player = new CommonPlayer({ left: config, top: args[0], width: args[1], height: args[2] });
    }
    else {
        player = new CommonPlayer(config);
    }
    player.type = 0;
    return player;
}
/**
 * 创建通用直播播放器实例
 * @param {(number | IBaseConfig)} config 播放器配置 当传入数字类型时表示left参数值
 * @param {...Array<number>} args top、width、height参数值
 * @returns {CommonPlayer} 播放器实例
 * @example
 * let player = Player.createLivePlayer({ left: 0, top: 0, width: 1920, height: 1080 });
 * let player = Player.createLivePlayer(0, 0, 1920, 1080);
 */
export function createLivePlayer(config, ...args) {
    let player;
    if (typeof config === 'number') {
        player = new CommonPlayer({ left: config, top: args[0], width: args[1], height: args[2] });
    }
    else {
        player = new CommonPlayer(config);
    }
    player.type = 1;
    return player;
}
/**
 * 创建PIP播放器实例
 * @param {(number | IBaseConfig)} config 播放器配置 当传入数字类型时表示left参数值
 * @param {...Array<number>} args top、width、height参数值
 * @returns {CommonPlayer} 播放器实例
 * @example
 * let player = Player.createPipPlayer({ left: 0, top: 0, width: 1920, height: 1080 });
 * let player = Player.createPipPlayer(0, 0, 1920, 1080);
 */
export function createPipPlayer(config, ...args) {
    let player;
    if (typeof config === 'number') {
        player = new CommonPlayer({ left: config, top: args[0], width: args[1], height: args[2] }, 'PIP');
    }
    else {
        player = new CommonPlayer(config, 'PIP');
    }
    player.type = 1;
    return player;
}
/**
 * 创建Mosaic播放器实例
 * @param {(number | IBaseConfig)} config 播放器配置 当传入数字类型时表示left参数值
 * @param {...Array<number>} args top、width、height参数值
 * @returns {CommonPlayer} 播放器实例
 * @example
 * let player = Player.createMosaicPlayer({ left: 0, top: 0, width: 1920, height: 1080 });
 * let player = Player.createMosaicPlayer(0, 0, 1920, 1080);
 */
export function createMosaicPlayer(config, ...args) {
    let player;
    if (typeof config === 'number') {
        player = new CommonPlayer({ left: config, top: args[0], width: args[1], height: args[2] }, 'MOSAIC');
    }
    else {
        player = new CommonPlayer(config, 'MOSAIC');
    }
    player.type = 1;
    return player;
}
/**
 * 获取机顶盒触发的Utility事件
 * @returns {string}
 */
export function getUtilityEvent() {
    try {
        // @ts-ignore stb自带Utility对象
        const eventJson = Utility.getEvent();
        let key;
        for (key in UtilityEvent) {
            if (Object.prototype.hasOwnProperty.call(UtilityEvent, key)) {
                const element = UtilityEvent[key];
                if (eventJson.indexOf(element) !== -1)
                    return element;
            }
        }
    }
    catch {
        console.error('[Utility] is not supported in this environment');
    }
    return UtilityEvent.UNSUPPORTED;
}
